Mutex and a Semaphore
C#’s lock statement is sufficient for many synchronization needs, some situations, such as restricting access to a shared resource, are sometimes more conveniently handled by other synchronization mechanisms built into the .NET Framework. The two described here are related to each other: mutexes and semaphores.
Mutex
A mutex is a mutually exclusive synchronization object. This means that it can be acquired by one and only one thread at a time. The mutex is designed for those situations in which a shared resource can be used by only one thread at a time. For example, imagine a log file that is shared by several processes, but only one process can write to that file at any one time. A mutex is the perfect synchronization device to handle this situation.
The mutex is supported by the System.Thread.Mutex class. It has several constructors.
public Mutex( )
public Mutex(bool owned)
To acquire the mutex, your code will call WaitOne( ) on the mutex. This method is inherited by Mutex from the Thread.WaitHandle class
When your code no longer needs ownership of the mutex, it releases it by calling ReleaseMutex( ).
Program on Mutex
using System;
using System.Threading;
class SharedRes
{
public static int count = 0;
public static Mutex mtx = new Mutex();
}
class IncThread
{
int num;
public Thread thrd;
public IncThread(string name, int n)
{
thrd = new Thread(this.run);
num = n;
thrd.Name = name;
thrd.Start();
}
void run()
{
Console.WriteLine(thrd.Name + " is waiting for the mutex.");
SharedRes.mtx.WaitOne();
Console.WriteLine(thrd.Name + " acquires the mutex.");
do
{
Thread.Sleep(500);
SharedRes.count++;
Console.WriteLine("In " + thrd.Name +
", SharedRes.count is " + SharedRes.count);
num--;
} while (num > 0);
Console.WriteLine(thrd.Name + " releases the mutex.");
// Release the Mutex.
SharedRes.mtx.ReleaseMutex();
}
}
class DecThread
{
int num;
public Thread thrd;
public DecThread(string name, int n)
{
thrd = new Thread(new ThreadStart(this.run));
num = n;
thrd.Name = name;
thrd.Start();
}
void run()
{
Console.WriteLine(thrd.Name + " is waiting for the mutex.");
// Acquire the Mutex.
SharedRes.mtx.WaitOne();
Console.WriteLine(thrd.Name + " acquires the mutex.");
do
{
Thread.Sleep(500);
SharedRes.count--;
Console.WriteLine("In " + thrd.Name +
", SharedRes.count is " + SharedRes.count);
num--;
} while (num > 0);
Console.WriteLine(thrd.Name + " releases the mutex.");
// Release the Mutex.
SharedRes.mtx.ReleaseMutex();
}
}
class vision
{
public static void Main()
{
IncThread mt1 = new IncThread("Vision Increment Thread", 5);
DecThread mt2 = new DecThread("Vision Decrement Thread", 5);
mt1.thrd.Join();
mt2.thrd.Join();
}
}
Semaphore
A semaphore is similar to a mutex except that it can grant more than one thread access to a shared resource at the same time. Thus, the semaphore is useful when a collection of resources are being synchronized.
Semaphores are especially useful in situations in which a shared resource consists of a group or pool. For example, a collection of network connections, any of which can be used for communication, is a resource pool. A thread needing a network connection doesn’t care which one it gets. In this case, a semaphore offers a convenient mechanism to manage access to the connections.
The semaphore is implemented by System.Thread.Semaphore. It has several constructors.
public Semaphore(int initial, int max)
Here, initial specifies the initial value of the semaphore permit counter, which is the number of permits available. The maximum value of the counter is passed in max.
WaitOne( ) waits until the semaphore on which it is called can be acquired.
When your code no longer needs ownership of the semaphore, it releases it by calling Release( ).
public int Release( )
public int Release(int num)
program on Semaphore
using System;
using System.Threading;
// This thread allows only two instances of itself
// to run at any one time.
class abc
{
public Thread thrd;
// This creates a semaphore that allows up to 2
// permits to be granted and that initially has
// two permits available.
static Semaphore sem = new Semaphore(2, 2);
public abc(string name)
{
thrd = new Thread(this.run);
thrd.Name = name;
thrd.Start();
}
// Entry point of thread.
void run()
{
Console.WriteLine(thrd.Name + " is waiting for a permit.");
sem.WaitOne();
Console.WriteLine(thrd.Name + " acquires a permit.");
for (char ch = 'A'; ch < 'D'; ch++)
{
Console.WriteLine(thrd.Name + " : " + ch + " ");
Thread.Sleep(500);
}
Console.WriteLine(thrd.Name + " releases a permit.");
// Release the semaphore.
sem.Release();
}
}
class Vision
{
public static void Main()
{
// Construct three threads.
abc mt1 = new abc("Thread #1");
abc mt2 = new abc("Thread #2");
abc mt3 = new abc("Thread #3");
mt1.thrd.Join();
mt2.thrd.Join();
mt3.thrd.Join();
}
}